///\todo upgrade

//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _CTEXTLAYOUT_H_
#define _CTEXTLAYOUT_H_

#include <buola/image/glyph.h>
#include <buola/image/ctextrun.h>

#include <unicode/ubidi.h>
#include <unicode/uscript.h>

namespace buola { namespace img {

class CTextLayout
{
public:
    struct SCursor
    {
        SCursor() {}
        SCursor(int pIndex,bool pTrailing=false)
            :   mIndex(pIndex),
                mTrailing(pTrailing)
        {}

        void Set(int pIndex,bool pTrailing=false)
        {
            mIndex=pIndex;
            mTrailing=pTrailing;
        }

        int AbsIndex() const
        {
            return mIndex+(mTrailing?1:0);
        }

        bool operator==(const SCursor &pCursor) const
        {
            return (mIndex==pCursor.mIndex&&mTrailing==pCursor.mTrailing);
        }

        int mIndex;
        bool mTrailing;
    };

    struct SVisual
    {
        TFontIndex mFont;
    };

    struct SAnalysis
    {
        UBiDiLevel mLevel;
        UScriptCode mScript;
        bool mRTL;
        TFontIndex mFont;
        int mFirstGlyph;
        int mGlyphCount;
    };

    struct SLine
    {
        double mTop;
        double mBottom;
    };

    struct SGlyph
    {
        TFontIndex mFont;
        TGlyphIndex mGlyph;
        double mAdvance;
        CPoint_d mOffset;
        CPoint_d mPos;
    };

    enum ECursorMove
    {
        CURSOR_LEFT,
        CURSOR_RIGHT,
        CURSOR_UP,
        CURSOR_DOWN,
        CURSOR_HOME,
        CURSOR_END
    };

    enum EWrapMode
    {
        WRAP_WORD,
        WRAP_CHAR,
        WRAP_WORD_CHAR
    };

    enum EEllipsizeMode
    {
        ELLIPSIZE_NONE,
        ELLIPSIZE_START,
        ELLIPSIZE_MIDDLE,
        ELLIPSIZE_END
    };

    enum EAlignMode
    {
        ALIGN_LEFT=0,
        ALIGN_CENTER=1,
        ALIGN_RIGHT=2,
        ALIGN_JUSTIFY=3,
        ALIGN_RIGHTJUSTIFY=4
    };

private:
    enum EFlags
    {
        FLAG_NONE=0,
        FLAG_WIDTH=(1<<0),
        FLAG_WIDTHCOLS=(1<<1),
        FLAG_HEIGHT=(1<<2),
        FLAG_HEIGHTLINES=(1<<3),
        VALID_ANALYSIS=(1<<5),
        VALID_GLYPHS=(1<<6),
        VALID_LAYOUT=(1<<7),
        VALID_ALL=VALID_ANALYSIS|VALID_GLYPHS|VALID_LAYOUT
    };

    DECLARE_FRIEND_ENUM_BITOPS(EFlags)

public:
    CTextLayout();
    CTextLayout(const std::wstring &pText);

    ~CTextLayout();

    const std::wstring &GetText()   {   return mText;   }
    void SetText(const std::wstring &pText);

    void SetDefaultFont(PFont pFont);

    void SetWidth(double pW);
    void SetHeight(double pH);
    void SetWidthCols(int pW);
    void SetHeightLines(int pH);
    void UnsetWidth();
    void UnsetHeight();

    void SetWrapMode(EWrapMode pMode);
    void SetEllipsizeMode(EEllipsizeMode pMode);
    void SetAlignMode(EAlignMode pMode);

    const CSize_d &GetSize();

    CPoint_d GetPositionOffset(ETextPos pPos);

    void Draw(const CPoint_d &pPos,CGC *pGC,
                        ETextPos pPosRef=ETextPos::TOPLEFT);

    void FillBack(const SCursor &pFrom,const SCursor &pTo,
        const CPoint_d &pPos,CGC *pGC,ETextPos pPosRef=ETextPos::TOPLEFT);

    //!returns the position of the n-th character within the layout
    CPoint_d GetPos(int pN);

    //!returns the cursor rectangle for a cursor position
    CRect_d GetCursorPos(const SCursor &pCursor);

    //!returns the index of the character at pPos
    int GetIndex(const CPoint_d &pPos);

    //!returns the index where to place the cursor at pPos
    SCursor GetCursor(const CPoint_d &pPos);

    void MoveCursor(SCursor &pCursor,ECursorMove pMove);

    void InsertText(SCursor &pCursor,const std::wstring &pString);
    void InsertChar(SCursor &pCursor,wchar_t pChar);
    void EraseChar(SCursor &pCursor,bool pBack);

private:
    void CalcAnalysis();
    void CalcGlyphs();
    void CalcLines();
    void CalcLayout();

private:
    EFlags mFlags;

    std::wstring mText;
    std::u16string mUText;

    PFont mDefaultFont;

    CSize_d mWrapSize;
    EWrapMode mWrapMode;
    EEllipsizeMode mEllipsizeMode;
    EAlignMode mAlignMode;

    CTextRun<UBiDiLevel> mBidiRun;      //limits in characters
    CTextRun<UScriptCode> mScriptsRun;  //limits in characters
    CTextRun<TFontIndex> mSubFontRun;   //limits in characters
    CTextRun<SAnalysis> mAnalysisRun;   //limits in characters
    CTextRun<SLine> mLinesRun;          //y of each, limits in characters
    CTextRun<SVisual> mVisualRun;       //limits in glyphs

    std::vector<SGlyph> mGlyphs;
    std::vector<int> mCharToGlyphMap;
    std::vector<int> mGlyphIndices; //glyphs sorted

    CSize_d mSize;

    //icu objects
    UBiDi *mBiDi;
};

/*namespace img*/ } /*namespace buola*/ }

#endif
